package corej.prj.commandlinebank.bamclient;

import corej.prj.commandlinebank.exception.*;
import corej.prj.commandlinebank.model.*;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class Bank {
    // ����ģʽ
    private static Bank bank = new Bank();

    private Bank() {
    }

    public static Bank newInstance() {
        return bank;
    }

    /*
      * keyΪLong id��valueΪAccount����
      */
    private Map as = new HashMap();

    // �����ʻ�
    public Account register(String pass1, String pass2, String name,
                            String personId, String email, int type) throws RegisterException {
        if (!(pass1.equals(pass2))) {
            throw new RegisterException("}���������벻һ�£�");
        }
        Account c = null;
        if (type == 0)
            c = new SavingAccount(pass1, name, personId, email);
        if (type == 1)
            c = new CreditAccount(pass1, name, personId, email);
        if (type == 2)
            c = new LoanSavingAccount(pass1, name, personId, email);
        if (type == 3)
            c = new LoanCreditAccount(pass1, name, personId, email);

        as.put(new Long(c.getId()), c);

        return c;
    }

    // ��¼
    public Account login(long id, String password) throws LoginException {
        Account c = this.findAccountById(id);
        if (c == null) {
            throw new LoginException("id " + id + " ������");
        }
        String p = c.getPassword();
        if (p.equals(password)) {
            System.out.println("Welcom back, " + c.getName());
            return c;
        } else {
            throw new LoginException("�������");
        }
    }

    // ��Ǯ
    public Account deposit(long id, double money) {
        Account c = this.findAccountById(id);
        c.deposit(money);
        return c;
    }

    // ȡǮ
    public Account withdraw(long id, double money)
            throws BalanceNotEnoughException {
        Account c = this.findAccountById(id);
        c.withdraw(money);
        return c;
    }

    // �趨͸֧���
    public Account setCeiling(long id, double ceiling) {
        Account c = this.findAccountById(id);
        if (c instanceof CreditAccount) {
            CreditAccount ca = (CreditAccount) c;
            ca.setCeiling(ceiling);
        }
        return c;
        // û��д��ʹ����CreditAccount�����
    }

    // ���
    public Account requestLoan(long id, double money) {
        Account c = this.findAccountById(id);
        if (c instanceof Loanable) {
            Loanable l = (Loanable) c;
            l.requestLoan(money);
        }
        return c;
    }

    // ����
    public Account payLoan(long id, double money) throws LoanException,
            BalanceNotEnoughException {
        Account c = this.findAccountById(id);
        if (c instanceof Loanable) {
            Loanable l = (Loanable) c;
            l.payLoan(money);
        }
        return c;
    }

    // ����ܴ����
    public double getTotalBalance() {
        double result = 0;

        Collection values = as.values();
        Iterator it = values.iterator();
        while (it.hasNext()) {
            Object obj = it.next();
            if (obj instanceof Account) {
                Account c = (Account) obj;
                result += c.getBalance();
            }
        }
        return result;
    }

    // �����͸֧���
    public double getTotalCeiling() {
        double result = 0;

        Collection values = as.values();
        Iterator it = values.iterator();
        while (it.hasNext()) {
            Object obj = it.next();
            if (obj instanceof CreditAccount) {
                CreditAccount c = (CreditAccount) obj;
                result += c.getCeiling();
            }
        }
        return result;
    }

    // ����ܴ����
    public double getTotalLoan() {
        double result = 0;

        Collection values = as.values();
        Iterator it = values.iterator();
        while (it.hasNext()) {
            Object obj = it.next();
            if (obj instanceof Loanable) {
                Loanable la = (Loanable) obj;
                result += la.getLoan();
            }
        }
        return result;
    }

    // ����û����ʲ�����----------------δ���-------------------------------
    public void printUserSort() {
        class User implements Comparable {
            private String personId;

            private double money;

            public User(String personId) {
                this.personId = personId;
            }

            public void addAccount(double money) {
                this.money += money;
            }

            public String toString() {
                return this.personId + ": " + money;
            }

            public int compareTo(Object obj) {
                User u = (User) obj;
                if (this.money < u.money)
                    return 1;
                else if (this.money > u.money)
                    return -1;
                else
                    return this.personId.compareTo(u.personId);
            }
        }
    }

    /*
      * ��HashSet��ͨ��id�ҵ��ʻ� ��Account login����������ʹ��
      */
    private Account findAccountById(long id) {
        Object value = as.get(new Long(id));
        return (Account) value;
    }

    public static void main(String[] args) {
        Bank b = Bank.newInstance();
        try {
            b.register("123", "123", "huxz", "123456", "huxz@tarena.com.cn", 0);
            b.register("123", "123", "huxz", "123456", "huxz@tarena.com.cn", 0);
            b.register("123", "123", "liucy", "123457", "liucy@tarena.com.cn",
                    0);
            b.register("123", "123", "liucy", "123457", "liucy@tarena.com.cn",
                    0);
            b.register("123", "123", "liucy", "123457", "liucy@tarena.com.cn",
                    0);
            b.deposit(100001, 200000);
            b.deposit(100002, 2000000);

            b.deposit(100003, 5000);
            b.deposit(100004, 20000);
            b.deposit(100005, 100000);

            System.out.println(b.getTotalBalance());
            System.out.println(b.getTotalCeiling());
            System.out.println(b.getTotalLoan());

            b.printUserSort();

        } catch (BusinessException e) {
            e.printStackTrace();
        }
    }

}
